home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-11 / grumptem.zip / GENGRUMP.TEM < prev    next >
Text File  |  1993-01-04  |  36KB  |  1,154 lines

  1. <<TITLE General.tem Modified to include Optional Grumpfish Popups.>>
  2. <<uicode>>
  3.  
  4. ** ** ** ** ------------------------------------ ** ** ** **
  5.  
  6. ** Modified 1/23/90 to include Grumpfish Popup programs
  7. ** Modifications by John H. Stolte, Sr. 1/23/90
  8. ** Copyright to Modifications (c) 1990 Medco Systems, Inc.
  9. ** The Modifications are For Clipper Summer 87 only, however you can still
  10. ** use this template for eveything else, it just wont generate Grump calls
  11. **
  12. ** At generation time, if you answer "YES" to the question "Are you generating
  13. ** a main file (first one called), you will be prompted for "Do you want to
  14. ** Include the Grumpfish Popup Utilities?"  If you say "YES" you will then be
  15. ** asked for each one: GrumpHelp, Calculator, Notepad, Appointment Calendar,
  16. ** Rolodex/Phone Dialer.  Each one that you answer yes to will be included at
  17. ** top of your generated code.  If you want to modify the way it is setup (it
  18. ** is set up the way _I_ like it) make the appropriate changes in STDgrump.TLB
  19. **
  20. ** Don't forget to list the appropriate Grumpfish Libraries in your LINK command
  21. **
  22. ** ** ** ** ------------------------------------ ** ** ** **
  23.  
  24.  
  25.  
  26.  
  27.  
  28. *   !! Coming attractions !!
  29. * 2.    dBASE3+ cannot tolerate UDFs !
  30. *
  31. ****************************************************************************
  32. *            Customization                       *
  33. *            -------------                       *
  34. *                                       *
  35. *    To add your own function(s) to GENERAL's standard set,             *
  36. *    follow the steps below.  These steps refer to locations in       *
  37. *    this template which are marked with the legend "- Custom n -"       *
  38. *    where n is the step.                           *
  39. *                                       *
  40. * 1.    Find the legend "- Custom 1 -" and add a new UI private        *
  41. *    variable named xxxx_words (xxxx should be a mnemonic for       *
  42. *    your new function).                           *
  43. *                                       *
  44. * 2.    Find the legend "- Custom 2 -" and assign to the new variable       *
  45. *    an uppercase string containing all the legitimate keywords       *
  46. *    for your new function.    Terminate each word with a space       *
  47. * (including the last word).             *
  48. *                                       *
  49. * 3.    Enter at "- Custom 3 -" a string containing the name of your       *
  50. *    new function (in uppercase, MyFunc, say), repeated as many       *
  51. *    times as there are variations of your keyword in the string       *
  52. *    of step 2. The repeats must all be terminated by a space.       *
  53. *                                       *
  54. * 4.    Find the legend "- Custom 4 -" in this file, and before it       *
  55. *    insert the lines:                           *
  56. *        <<if want_proc(xxxx_words)>>                   *
  57. *    (See step 1 for xxxx-words.)                       *
  58. *    Follow this line with your function (or procedure) declaration.    *
  59. *    But do not use the actual name for the function or procedure,       *
  60. *    use instead the following form:                    *
  61. *        FUNCTION {uniqname("MyFunc")}                   *
  62. *    where "MyFunc" is the name of your function or procedure       *
  63. *    as you specified in step 3.                       *
  64. *                                       *
  65. * 5.    Start writing your new function (or procedure) in Dbase, just       *
  66. *    as you would if you were writing plain Dbase.               *
  67. *                                       *
  68. * 6.    After the last line in your new function, enter the line:       *
  69. *    <<endif>>                               *
  70. ****************************************************************************
  71.  
  72. *          ------- Template startup -------
  73. *   ┌──────────────────────────────────────────┐
  74. *   │    Load libraries used by this template   │
  75. *   └──────────────────────────────────────────┘
  76.  
  77. load_lib("stdgrump")  ** load basic stuff  && Replaces Stdfuns.tlb
  78. load_lib("slots")
  79. load_lib("dbffuns")
  80. load_lib("vars")
  81. load_lib("boxes")
  82. load_lib("_general")    ** Supporting UI functions for this template
  83. load_lib("_genproc")    ** Procedure generation routines for this template
  84.  
  85. do case             ** load appropriate display library
  86.   case db3plus() .or. Fox1()
  87.     load_lib("disp3p")
  88.     load_lib("optfuns")
  89.   case Clipper() .or. Fox2()
  90.     load_lib("dispclip")
  91.     load_lib("optfuns")
  92.   case dBASE4()
  93.     load_lib("dispdb4")
  94.     load_lib("optdb4")
  95.   case QS()
  96.     load_lib("disp3p")
  97.     load_lib("optfuns")
  98.   otherwise
  99.     * for the moment, let's load the III PLUS library as a default...
  100.     load_lib("disp3p")
  101.     load_lib("optfuns")
  102. endcase
  103.  
  104. *   ┌─────────────────────────────────────────────────────────┐
  105. *   │    Set-up all option keyword lists and their procedures  │
  106. *   └─────────────────────────────────────────────────────────┘
  107.  
  108. private opt_words, opt_procs
  109. private edit_words, add_words, next_words, prev_words, ;
  110.     top_words, bot_words, ;
  111.     goto_words, del_words, find_words        ** - Custom 1 -
  112. edit_words = "EDIT UPDATE CHANGE "
  113. add_words  = "ADD APPEND NEW "
  114. next_words = "NEXT "
  115. prev_words = "PREVIOUS "
  116. top_words  = "TOP FIRST "
  117. bot_words  = "BOTTOM LAST "
  118. goto_words = "GOTO JUMP "
  119. del_words  = "DELETE ERASE KILL "
  120. find_words = "FIND SEARCH "
  121. * - Custom 2 -
  122. opt_words =edit_words+add_words+next_words+prev_words+top_words+bot_words+goto_words+del_words+find_words
  123. opt_procs = "EDITREC EDITREC EDITREC " +;
  124.         "ADDREC ADDREC ADDREC "    +;
  125.         "NEXTREC "               +;
  126.         "PREVREC "               +;
  127.         "FIRSTREC FIRSTREC "       +;
  128.         "LASTREC LASTREC "           +;
  129.         "GOTOREC GOTOREC "           +;
  130.         "DELREC DELREC DELREC "    +;
  131.         "FINDREC FINDREC "        ** +; - Custom 3 -
  132.  
  133.  
  134. *    ┌───────────────────────────────────────────────────────┐
  135. *    │    Use UI variables for inkey and readkey values    │
  136. *    └───────────────────────────────────────────────────────┘
  137.  
  138. private IKesc, IKup, IKdn
  139. IKesc = 27
  140. IKup = 5
  141. IKdn = 24
  142. IKPgUp = 18
  143. IKPgDn = 3
  144.  
  145. private LRKup, LRKpgup, LRKdn, LRKpgdn, Rkesc, LRKret, LRKctrlw, LRKhome, LRKend
  146. if Clipper()        ** for various reasons, we must use lastkey in Clipper
  147.     LRKup   = IKup
  148.     LRKpgup = 18
  149.     LRKdn   = IKdn
  150.     LRKpgdn = 3
  151.     LRKesc  = IKesc
  152.     LRKret  = 13
  153.     LRKctrlw= 23
  154.     LRKhome = 1
  155.     LRKend  = 6
  156. else
  157.     LRKup   =  4
  158.     LRKpgup =  6
  159.     LRKdn   =  5
  160.     LRKpgdn =  7
  161.     LRKesc  = 12
  162.     LRKret  = 15
  163.     LRKctrlw= 14
  164.     LRKhome =  2
  165.     LRKend  =  3
  166. endif
  167. private RKPgUp, RKPgDn
  168. RKPgUp = 6
  169. RKPgDn = 7
  170.  
  171. *    ┌────────────────────────────────────────────┐
  172. *    │        MAIN DECLARATIONS         │
  173. *    └────────────────────────────────────────────┘
  174.  
  175. private i, j        ** Counters.
  176. private b        ** A box
  177. private s        ** Any string
  178. private actoks        ** Array of tokens from option-action line.
  179. private acts        ** Option-action line.
  180. private ans        ** Result from a call to ask_for...
  181. private fldclr        ** A typical field color spec.
  182. private got_ip_flds    ** Logical: True if there are input fields on screen.
  183. private line        ** Used for constructing output lines.
  184. private loclr        ** Unselected color in menu.
  185. private hiclr        ** Selected color in menu.
  186. private mainsys     ** Logical: Generating first called in system ==> prggen.
  187. private mainspec    ** Logical: MAIN or MODULE specified.
  188. private prggen        ** Logical: Output to a new PRG file.
  189. private module        ** Name of o/p file dir and tag stripped.
  190. private procname    ** Name of main procedure if .not.prggen.
  191. private prefix        ** Prefix for proc.names.  Only used if .not.mainsys.
  192. private new        ** Logical: O/p file is created (not appended).
  193. private nwords        ** # keywords recognised by GENERAL in option-actions.
  194. private words        ** Keyword token array of length nwords.
  195. private procs        ** Token array of ancilliary proc.root names.
  196. private separate_procs    ** separate_procs == procfile .and. prggen.
  197. private have_procs    ** False only for single-page puretext otherwise true.
  198. private need_result    ** == .not.prggen .and. (singleopt.or.puretext)
  199. private savescreen    ** Logical: Popup-menu and flavor can save the screen.
  200. private scrbufname    ** Name of Dbase variable to save the screen into.
  201. private genpopup    ** == menubox.popup. Literally: generate menu redisplay.
  202. private pop_flavor    ** Flavor can restore a screen.
  203. private npoptxt     ** Number of fixed text popups, usually a popup help.
  204. private poptext     ** Text-only box(es) to popup
  205. private singleopt    ** Keyword for single-purpose function else null.
  206. private singleproc    ** Name of ancilliary function reqd. for single-purpose screen.
  207. private singleadd    ** Single purpose append screen.
  208. private puremenu    ** Logical: Options but no fields.
  209. private puretext    ** Logical: No options and no fields.
  210. private npages        ** # of data screen boxes in multi-page design.
  211. private pages        ** Box array of pages in multi-page design.
  212. private toppage     ** Top page in multi-page design:  One that hides others.
  213. private fundecl     ** Declarative for Dbase UDF: in Fox "PROC" else "FUNCTION".
  214. private msgbox        ** Box where miscellaneous messages can appear, if any.
  215. private menubox     ** Box containing all screen options, if any.
  216. private menuname    ** Name of menu proc, null for inline menu.
  217. private isbox        ** True if menubox is not background screen.
  218. private got_opt     ** False until we know of any option or single-purpose.
  219. private msgr        ** Message box row
  220. private msgc        ** Message box col
  221. private msgwidth    ** Message box width
  222. private fkeylen     ** Display length of search key.
  223. private mainfile    ** Name of primary file: comment in separate proc file
  224. private procfile    ** Name of procedure file of any kind, if any.
  225.             **(None only if generating PRG and ancilliaries included).
  226. private append_proc    ** Logical: Separate procs are appended to existing procfile.
  227. private edit_dbfs    ** Logical array: .t. if i.th DBF can be modified.
  228. private pre_lock    ** Logical: Generate code to lock rec during data entry.
  229. private split_read    ** Logical: Generate separate READ for every @..GET.
  230. private need_dispmrec    ** Logical: dispmrec procedure is required.
  231. private nflds        ** Input field count.
  232. private calculations    ** True if any there are any calculated variables
  233. private calcfields    ** True if any there are any calculated fields
  234. private ixcheck     ** True if index file checking to be generated.
  235. private udfs        ** Language has U.D.F.'s
  236.  
  237. ** ** ** ** ------------------------------------ ** ** ** **
  238. ** Rev 1/23/90 JHS modifications for Grumpfish desktop utils /variables
  239. ** ** ** ** ------------------------------------ ** ** ** **
  240. ghelp  = .f.
  241. gphone = .f.
  242. gdate  = .f.
  243. gcalc  = .f.
  244. gnote  = .f.
  245. ** ** ** ** ------------------------------------ ** ** ** **
  246. ** End  Rev 1/23/90 Grumpfish Modifications for variable declaration
  247. ** see line 401 for the rest of the mods and also see stdgrump.tlb
  248. ** ** ** ** ------------------------------------ ** ** ** **
  249.  
  250. *    ┌─────────────────────────────────────────────────┐
  251. *    │    Determine language dependent features      │
  252. *    └─────────────────────────────────────────────────┘
  253.  
  254. pop_flavor = Clipper() .or. Fox() .or. dBASE4() .or. QS()
  255. udfs = Fox() .or. Clipper() .or. dBASE4()
  256. fundecl = (Fox() .or. .not.udfs) ? "PROC" : "FUNCTION"
  257. * (QuickSilver UDF's are too difficult to implement -- probably easier
  258. *  for WordTech to implement real UDF's.)
  259. *    ┌─────────────────────────────────────────────────┐
  260. *    │    Find any specially recognized boxes      │
  261. *    └─────────────────────────────────────────────────┘
  262.  
  263. * Find command box.  If none, use background screen box.
  264. cmdbox = screen
  265. for all boxes
  266.     if at("PARAM", upper(box.name)) .or. at("PARAM", upper(box.slot1))
  267.     cmdbox = box
  268.     exit
  269.     endif
  270. endfor
  271.  
  272. * Find a message box, if there is any.
  273. msgbox = grab_box("MESSAGE")
  274. if msgbox
  275.     i = msgbox.outline.type
  276.     msgr = msgbox.row + i
  277.     msgc = msgbox.col + i
  278.     msgwidth = msgbox.width - i - i
  279. else
  280.     msgr = 24
  281.     msgc = 1
  282.     msgwidth = 40
  283. endif
  284.  
  285. * Find the menu box.  If none, it must be the background screen.
  286. menubox = grab_box("MENU")
  287. isbox = .t.
  288. if .not.menubox
  289.     ** No named menu box, search for it.
  290.     for all boxes
  291.     for all options in box
  292.         if menubox
  293.         if menubox <> box
  294.            gen_error(;
  295.              "All options should be contained in one box or in no box")
  296.         endif
  297.         else
  298.         menubox = box
  299.         endif
  300.     endfor
  301.     endfor
  302.     if .not.menubox
  303.     isbox = .f.
  304.     menubox = screen
  305.     endif
  306. endif
  307.  
  308. * Check to see if multi-page screen is required.
  309. npages = 0
  310. pages = array("BOX", 10)    ** Up to 10 pages on screen
  311. for all boxes where .not.box.popup .and. box <> menubox
  312.     i = slots_key_num(box, "PAGE", 0)
  313.     if i > 10
  314.     gen_error("Max.number of pages on screen (10) exceeded.")
  315.     endif
  316.     npages = max(i, npages)
  317.     if i
  318.     got_var = .f.
  319.     for all vars in box
  320.         got_var = .t.
  321.         exit
  322.     endfor
  323.     pages[i] = box
  324.     toppage = i    ** will end up being the uppermost box on screen
  325.     endif
  326. endfor
  327.  
  328. *    ┌──────────────────────────────────────────────────────────┐
  329. *    │           System Characteristics.           │
  330. *    ├──────────────────────────────────────────────────────────┤
  331. *    │    Are there fields?  Are there calculated vars?       │
  332. *    └──────────────────────────────────────────────────────────┘
  333.  
  334. * Find typical field color
  335. fldclr = ""
  336. got_ip_flds = .f.
  337. for all fields where normal_var(field)
  338.     fldclr = field.color
  339.     if field.input
  340.     got_ip_flds = .t.
  341.     exit
  342.     endif
  343. endfor
  344. puremenu = .not.fldclr        ** No fields, assume it's a pure menu
  345.  
  346. * Find if there are any calculated variables
  347. calculations = .f.
  348. calcfields = .f.
  349. for all vars where normal_var(var)
  350.      if .not.empty(var.calc_formula)
  351.     calculations = .t.
  352.     calcfields = var.isfield
  353.     exit when calcfields
  354.      endif
  355. endfor
  356.  
  357. *    ┌──────────────────────────────────────────────┐
  358. *    │        System Characteristics.           │
  359. *    │        Program Linkages           │
  360. *    ├──────────────────────────────────────────────┤
  361. *    │    Generating main program?  If not,      │
  362. *    │    generating procedure file?  Calling    │
  363. *    │    a proc.file?  Is is possible to        │
  364. *    │    call a proc.file?               │
  365. *    └──────────────────────────────────────────────┘
  366.  
  367. ************** Determine generation files and generation type ************
  368. * Explanation of flags used:
  369. * mainsys = .t.     if generating top-level PRG.
  370. * prggen  = .t.     if generating main module as PRG file.
  371. * append_proc = .t.    if generating PRG and procedures are appended
  372. *               to separate procfile.
  373. * separate_procs = .t.    if sub-procs go to separate prcedure file
  374. *            == prggen && procfile
  375. *
  376. * Explanation of strings used:
  377. * mainfile = main output file
  378. * procfile = second output file = mainfile if prggen is false.
  379. **************************************************************************
  380. prggen = .t.
  381. append_proc = .f.
  382. procfile = ""
  383. have_procs = .t.
  384. mainfile = file
  385. module = stripdir(striptag(file))
  386. procname = module
  387.  
  388.  
  389. * Find if this is to be a main program.
  390. do case
  391.   case slots_keyword(cmdbox, "MAIN")
  392.     mainsys = .t.
  393.  
  394.   case slots_keyword(cmdbox, "PROCFILE")
  395.     prggen = .f.
  396.  
  397.   case slots_keyword(cmdbox, "MODULE")
  398.     mainsys = .f.
  399.  
  400.   case ask_for_yn("Are you generating a main program (the first called)?")
  401.     mainsys = .t.
  402.  
  403. ** ** ** ** ------------------------------------ ** ** ** **
  404. ** Rev 1/23/90 jhs && acts on stdgrump.tlb to load grumpfish desktop utils
  405. ** if following responses to ask_for_yn() are yes
  406. ** ** ** ** ------------------------------------ ** ** ** **
  407.  
  408. ans =  ask_for_yn("Do you want to include the Grumpfish Popoup Utilities?")
  409. if summer87()
  410.   if ans
  411.     ghelp =   Ask_for_yn("Do you want to include the Grumpfish Help system?")
  412.  
  413.     gphone =   Ask_for_yn("Do you want to include the Grumpfish Rolodex/phone dialer?")
  414.  
  415.     gcalc = Ask_for_yn("Do you want to include the Grumpfish Popup Calculator?")
  416.  
  417.     gnote = Ask_for_yn("Do you want to include the Grumpfish Popup Notepad?")
  418.  
  419.     gdate = Ask_for_yn("Do you want to include the Grumpfish Appointment Calendar?")
  420.  
  421. endif
  422.   else
  423.     Gen_msg("You can only use Grumpfish Functions With Clipper Summer 87")
  424. endif
  425. ** ** ** ** ------------------------------------ ** ** ** **
  426. ** END Rev 1/23/90 jhs
  427. ** ** ** ** ------------------------------------ ** ** ** **
  428.  
  429.   case ask_for_yn("Do you want this module generated into a procedure file?")
  430.     prggen = .f.
  431.  
  432.  
  433.  
  434.   otherwise   ** Same as "MODULE"
  435.     mainsys = .f.
  436.     prggen = .t.
  437.  
  438. endcase
  439.  
  440. *    ┌──────────────────────────────────────────────┐
  441. *    │    Does this screen have a menu?           │
  442. *    │    If so, can any option actions call     │
  443. *    │    procs in another proc file?           │
  444. *    └──────────────────────────────────────────────┘
  445.  
  446. * Find any option and take lowlite color from it.
  447. got_opt = .f.
  448. loclr = 0
  449. hiclr = 0
  450. for all options in menubox
  451.     loclr = option.color_unselected
  452.     hiclr = option.color_selected
  453.     got_opt = .t.
  454.     exit
  455. endfor
  456.  
  457. if .not.prggen
  458. *    ┌────────────────────────────────────────────────────────────┐
  459. *    │    We're generating into a procedure file.              │
  460. *    │    Which file?  What name for the procedure?         │
  461. *    └────────────────────────────────────────────────────────────┘
  462.  
  463.     procfile = slots_key_param(cmdbox, "PROCFILE",0)
  464.     procname = slots_key_param(cmdbox, "PROCNAME", procname)
  465.  
  466.     if .not.procfile
  467.     * Procedure file generation but we don't yet know the proc filename.
  468.     procfile = get_procfile()
  469.     if .not.procfile
  470.         if .not.ask_for_yn("Same as output file you originally specified?")
  471.         gen_error("Generation stopped at user request")
  472.         endif
  473.         procfile = mainfile
  474.     else
  475.         * Appending to (possibly existing) procfile
  476.         new = .t.
  477.         if .not.file(procfile)
  478.         if .not.ask_for_yn("File {procfile} does not exists, create it?")
  479.             gen_error("Generation stopped at user request")
  480.         endif
  481.         else
  482.         if ask_for_yn("File exists.  Append to it?")
  483.             append_output(procfile)
  484.             new = .f.
  485.         endif
  486.         endif
  487.         if new
  488.         set_output(procfile)
  489.         mainfile = procfile
  490.         endif
  491.  
  492.         module = stripdir(striptag(procfile))
  493.         * generate procedure name prefix from module name
  494.         prefix = module
  495.         if !isalpha(prefix[1])
  496.         prefix = 's' + prefix
  497.         endif
  498.     endif
  499.     if .not.procname
  500.         procname = ask_for_string("Name of main procedure:")
  501.         if .not.procname
  502.         gen_error("Generation stopped")
  503.         endif
  504.     endif
  505.     endif        ** .not.procfile
  506.     * Should now create string of action procedure names, but our
  507.     * prefix is not yet constructed.  So do that first.
  508. endif            ** prggen
  509.  
  510. *   ┌───────────────────────────────────────────────────────┐
  511. *   │    Generate procedure name prefix from module name.    │
  512. *   │    This is used by uniqname() to generate proc names.  │
  513. *   └───────────────────────────────────────────────────────┘
  514. prefix = procname
  515. if !isalpha(prefix[1])
  516.     prefix = 's' + prefix
  517. endif
  518.  
  519. for i = 1 to len(prefix)
  520.     if !isalnum(prefix[i]) .and. prefix[i] <> '_'
  521.     prefix = strtran(prefix,prefix[i],'')
  522.     endif
  523. endfor
  524.  
  525. prefix = substr(prefix, 1, 3) + "_"
  526.  
  527.  
  528. menuname = uniqname("menu")
  529. if prggen
  530. *    ┌─────────────────────────────────────────────────────────────┐
  531. *    │    Check if user calls other proc files in option actions   │
  532. *    └─────────────────────────────────────────────────────────────┘
  533.     if got_opt
  534.     if slots_keyword(menubox, "INLINE") ;
  535.        .or. (cmdbox .and. slots_keyword(cmdbox, "INLINE"))
  536.          menuname = 0
  537.     endif
  538.     endif
  539. else
  540. *   ┌─────────────────────────────────────────────────────────────┐
  541. *   │    Now ready to create our string of action procedure names  │
  542. *   └─────────────────────────────────────────────────────────────┘
  543.     procs = get_tokens(opt_procs, " ")
  544.     opt_procs = ""
  545.     for i = 1 to len(procs)
  546.     opt_procs = opt_procs + uniqname(procs[i]) + " "
  547.     endfor
  548. endif
  549.  
  550. *    ┌─────────────────────────────────────────────────┐
  551. *    │          System Characteristics.          │
  552. *    ├─────────────────────────────────────────────────┤
  553. *    │  If this screen has no menu and no fields then  │
  554. *    │  it must be a text-only display program.      │
  555. *    └─────────────────────────────────────────────────┘
  556.  
  557. puretext =  puremenu .and. .not.got_opt
  558. if puretext
  559.     puremenu = .f.
  560.     have_procs = npages     ** Need procedures only if multi-page text.
  561. endif
  562.  
  563. npoptxt = 0
  564. if puretext
  565.     got_opt = .t.        ** Option is to display text
  566.     * Check if user just wants a popup box
  567.     for all boxes where box.popup
  568.     npoptxt++
  569.     poptext = box
  570.     endif
  571. endif
  572.  
  573. *    ┌─────────────────────────────────────────────────┐
  574. *    │        System Characteristics.          │
  575. *    ├─────────────────────────────────────────────────┤
  576. *    │ If this is a PRG file, should we send all the   │
  577. *    │ procedures (if any) to another file or this one?│
  578. *    └─────────────────────────────────────────────────┘
  579.  
  580. if mainsys .or. prggen
  581.     ** Generating into a main or sub-module PRG file
  582.     * Ask user where the several procedures/functions required by this
  583.     * PRG should go.
  584.     procfile = slots_key_param(cmdbox, "SUBPROCS", .f.)
  585.     if procfile
  586.     append_proc = slots_keyword(cmdbox, "APPEND")
  587.     endif
  588.  
  589.     if .not.procfile;
  590.        .and. have_procs;
  591.        .and. (QS() .or. ask_for_yn("Do you want procedures generated in a separate file?"))
  592.     procfile = get_procfile()
  593.     if .not.procfile
  594.         gen_error("Generation stopped at user request")
  595.     else
  596.         if file(procfile)
  597.         append_proc = ask_for_yn( ;
  598.           "Should I append to the existing text in {procfile}?")
  599.         endif
  600.     endif
  601.     endif
  602. endif
  603. separate_procs = procfile .and. prggen
  604.  
  605. *    ┌─────────────────────────────────────────────────────────┐
  606. *    │         System Characteristics.          │
  607. *    ├─────────────────────────────────────────────────────────┤
  608. *    │ If there's no menu and it's not a text display program, │
  609. *    │ what actions should be performed by generated program?  │
  610. *    └─────────────────────────────────────────────────────────┘
  611. singleopt = 0
  612. singleadd = .f.
  613. do while .not.got_opt
  614.     ans = gen_msg(;
  615.     "There are no options.  Which type of screen do you want to generate%n" +;
  616.     "  A(dd), D(elete), E(dit), or S(earch) screen? (Q to quit)")
  617.     got_opt = .t.
  618.     switch(upper(chr(ans)))
  619.       case "Q"
  620.     gen_error("Generation stopped at user request")
  621.       case "A"
  622.     singleopt = first_word(add_words)
  623.     singleproc = uniqname("addrec")
  624.     singleadd = .t.
  625.       case "D"
  626.     singleopt = first_word(del_words)
  627.     singleproc = uniqname("delrec")
  628.       case "E"
  629.     singleopt = first_word(edit_words)
  630.     singleproc = uniqname("editrec")
  631.       case "S"
  632.     singleopt = first_word(find_words)
  633.     singleproc = uniqname("findrec")
  634.       otherwise
  635.     got_opt = .f.
  636.     endsw
  637. enddo
  638.  
  639. *    ┌─────────────────────────────────────────────────────────┐
  640. *    │           System Characteristics.              │
  641. *    ├─────────────────────────────────────────────────────────┤
  642. *    │    Some last-minute language dependent stuff.      │
  643. *    └─────────────────────────────────────────────────────────┘
  644. *
  645. need_result = udfs .and. .not.prggen .and. (singleopt .or. puretext)
  646.  
  647. genpopup = .f.
  648. savescreen = .f.
  649. genpopup = menubox.popup
  650.  
  651. if genpopup .or. npoptxt
  652.     if pop_flavor
  653.     load_lib("popfuns")
  654.     savescreen = genpopup
  655.     endif
  656. endif
  657.  
  658. *    ┌───────────────────────────────────────────────────────────┐
  659. *    │         System Characteristics.            │
  660. *    ├───────────────────────────────────────────────────────────┤
  661. *    │ Check for an option mainly intended for expert users.     │
  662. *    │ See if designer wants full control over GET's and READ's. │
  663. *    └───────────────────────────────────────────────────────────┘
  664. *
  665. * Find if designer wants embedded READ's or special actions on @..GET's
  666. * Intention is to simulate of WHEN verb in dBASE4 for other flavors,
  667. * but allowing embedded READ's.
  668. * Eg: to allow adding of a record in a validation or lookup screen.
  669. split_read = .f.
  670. need_dispmrec = .f.
  671. ** EDIT or APPEND requested ?
  672. edit_or_append = want_proc(edit_words + add_words)
  673. if edit_or_append
  674.     * Need special version of disprec for dupe.fields in following circumstance:
  675.     need_dispmrec = singleopt .or. npages
  676.  
  677.     split_read = slots_keyword(cmdbox, "EMBEDDED")
  678.     if .not.split_read
  679.     * Check if there are any validations
  680.     have_valid = .f.
  681.     for all fields where field.input .and. normal_var(field)
  682.         if .not.empty(field.valid)
  683.         have_valid = .t.
  684.         exit
  685.         endif
  686.     endfor
  687.     if have_valid
  688.         split_read = ask_for_yn(;
  689.           "Do any of your validation functions do @..GET's and READ?")
  690.     endif
  691.     endif
  692. endif
  693.  
  694. *    ┌───────────────────────────────────────────────────────────┐
  695. *    │         System Characteristics.            │
  696. *    ├───────────────────────────────────────────────────────────┤
  697. *    │ Multi-user options.  Designer set the mulituser flag.     │
  698. *    │ So what kind of protection does s/he want?            │
  699. *    └───────────────────────────────────────────────────────────┘
  700.  
  701. * Multi-user preamble.
  702. lock_gen = .f.
  703. if multi .and. .not.puremenu
  704.     * See if user requires maximum safety in record locking
  705.  
  706.     i = slots_keyword(cmdbox, "LOCK")
  707.     if i
  708.     * Test words appearing before LOCK for options.
  709.     toks = get_tokens(upper(cmdbox.slots[i]))
  710.     for j = 1 to len(toks)
  711.         exit when toks[j] = "LOCK"
  712.     endfor
  713.  
  714.     for i = max(1,j-2) to j-1
  715.         switch(toks[i])
  716.           case "SCREEN"
  717.         pre_lock = .t.
  718.           case "SAFETY"
  719.         pre_lock = .t.
  720.           case "UPDATE"
  721.         pre_lock = .f.
  722.           case "GENPROC"
  723.         lock_gen = .t.
  724.         endsw
  725.     endfor
  726.  
  727.     else    ** i is zero
  728.     pre_lock = ask_for_yn(;
  729.        "Multi-user:  Should records be locked during entire edit sessions?")
  730.     lock_gen = ask_for_yn("Should I generate the lock-testing function?")
  731.     endif    ** i
  732.  
  733.  
  734.     * Find all dbf's that might be edited.
  735.     edit_dbfs = array("L", 40)
  736.     for all dbfs
  737.     if count > 40
  738.         gen_error("Too many dbf's for locking procedures")
  739.     endif
  740.     i = count
  741.     for all fields where field.dbf = dbf .and. normal_var(field)
  742.         edit_dbfs[i] = .t.
  743.         exit
  744.     endfor
  745.     endfor
  746. endif        ** Multi
  747.  
  748.  
  749. *    ┌────────────────────────────────────────────────────────┐
  750. *    │    End of System Characteristics Determination     │
  751. *    └────────────────────────────────────────────────────────┘
  752. *
  753. *
  754. *    ┌──────────────────────────────────────────────┐
  755. *    │        Code Generation            │
  756. *    └──────────────────────────────────────────────┘
  757. *
  758.  
  759. *
  760. *    ┌──────────────────────────────────────────────────────┐
  761. *    │           Code Generation.               │
  762. *    ├──────────────────────────────────────────────────────┤
  763. *    │  Insert comments describing program characteristics  │
  764. *    └──────────────────────────────────────────────────────┘
  765. ?"***"
  766. ?'*** {file} : {mainsys ? "standalone" : "submodule"} version.'
  767. do case
  768.     case singleopt
  769.     ?"*** Purpose: {singleopt}"
  770.     case puretext
  771.     ?"*** "
  772.     if npoptxt
  773.         ?? "Popup "
  774.     endif
  775.     ?? "Text display"
  776.     case puremenu
  777.     ?"*** Purpose: Menu"
  778.     other
  779.     * Write list of main options on screen.
  780.     ?"*** Actions: "
  781.  
  782.     words = get_tokens(opt_words)
  783.     nwords = len(words)
  784.     line = ""
  785.     for all options in menubox
  786.         s = ""
  787.         for i = 1 to len(option.action)
  788.         acts = upper(option.action[i])
  789.         loop when empty(acts)
  790.         actoks = get_tokens(acts)
  791.         for j = 1 to nwords
  792.             if words[j] = actoks[1]
  793.             s = words[j]
  794.             exit
  795.             endif
  796.         endfor
  797.         exit when s
  798.         endfor
  799.         loop when empty(s)
  800.  
  801.         if len(line) > 65
  802.         ?? line
  803.         ?"***        :"
  804.         line = ""
  805.         endif
  806.         if .not.empty(line)
  807.         s = ", " + s
  808.         endif
  809.         line = line + s
  810.     endfor
  811.     ?? line
  812. endcase
  813.  
  814. if have_procs
  815.     if separate_procs
  816.     ?"*** Supporting procedures are in file {procfile}"
  817.     else
  818.     ?"*** Supporting procedures are in this file."
  819.     endif        ** separate_procs
  820. endif
  821. <<enduicode>>
  822. ***
  823. *** Generated on {date}
  824. *** Source .WW file: {wwfile}
  825. *** Target environment: {flavor}
  826. ***
  827. <<uicode>>
  828. if .not.prggen
  829.     ?"PROCEDURE {procname}"
  830. endif
  831.  
  832. *    ┌─────────────────────────────────────────┐
  833. *    │         Code Generation.          │
  834. *    ├─────────────────────────────────────────┤
  835. *    │ Initial declarations and SET PROC's.    │
  836. *    │ Setup environment and open DBF's, NDX's │
  837. *    └─────────────────────────────────────────┘
  838. if .not.udfs .and. edit_or_append
  839.     ?"PUBLIC changed      && Needed for returning result from gets_proc"
  840. endif
  841. if mainsys .and. number_of_dbfs() > 0
  842.     ?"PRIVATE dbdir, ixdir"
  843. endif
  844. if npages
  845.     ?"PRIVATE PageNum"
  846. endif
  847.  
  848. if npages
  849.     if edit_or_append
  850.     ?"PRIVATE editing"
  851.     ?"editing = .F.         && True => display memvar values"
  852.     ?
  853.     endif
  854.     ?"PageNum = {toppage}       && Start with uppermost page"
  855. endif
  856. ?
  857.  
  858. if prggen
  859.     if .not. (CLipper() .or. QS() .or. dBXL())
  860.     ?"SET PROC TO {(procfile ? procfile : striptag(file))}"
  861.     endif
  862.     if    (Clipper() .and. separate_procs) .or. QS() .or. dBXL()
  863.     ?"SET PROC TO {striptag(stripdir(procfile))}"
  864.     endif
  865. endif          ** prggen
  866.  
  867.  
  868. *    ┌────────────────────────────────────────────────────────────────────┐
  869. *    │    Only generate environment setup and file opens for a main system  │
  870. *    └────────────────────────────────────────────────────────────────────┘
  871. if mainsys
  872.     ?"*** environment stuff"
  873.     env_setup()
  874.  
  875.     * Check that index files all exist
  876.     ixcheck = .t.
  877.     for all indexes
  878.     s = index.name
  879.     if .not.at('.', s)
  880.         s = s + ndxtag
  881.     endif
  882.     s = ndxdir + s
  883.     if .not.file(s)
  884.         if ask_for_yn("Warning: Index file missing.%n"+;
  885.          "  Do you want the generated program to create missing index files?")
  886.         ixcheck = .t.
  887.         else
  888.         gen_msg("You can use INDEX.TEM to generate an indexing program.")
  889.         endif
  890.         exit
  891.     endif
  892.     endfor
  893.  
  894.     if number_of_dbfs() > 0
  895.     ?
  896.     ?"* DBF initialization"
  897.     ?'dbdir = "{dbfdir}"'
  898.     ?'ixdir = "{ndxdir}"'
  899.     init_all_dbfs("dbdir","ixdir", ixcheck)
  900.     endif
  901. endif
  902.  
  903. if puretext        ** Special case.  Very little has to be generated
  904. *    ┌─────────────────────────────────────────┐
  905. *    │           Code Generation.       │
  906. *    ├─────────────────────────────────────────┤
  907. *    │  Do entire text-only display here.      │
  908. *    └─────────────────────────────────────────┘
  909.     if npoptxt .and. pop_flavor
  910.     scrbufname = "tx_save_buf"
  911.     ?
  912.     ?"PRIVATE {scrbufname}, key"
  913.     ?
  914.     if npoptxt > 1
  915.         poptext = screen  ** For several popup boxes, save entire screen
  916.         ? "*** Popup text"
  917.     else
  918.         ? "*** Popup box"
  919.     endif
  920.     call_save_screen(poptext, scrbufname)
  921.     if npages
  922.         display_start_MP()        ** Show boxes in form order
  923.         gen_npage_txt("key")    ** Multi-page switching
  924.     else
  925.         if npoptxt > 1
  926.         display_text()
  927.         else
  928.         display_box(poptext)
  929.         endif
  930.         gen_inkey("key")
  931.     endif
  932.     ?
  933.     call_restore_screen(poptext, scrbufname)
  934.     else    ** No popups
  935.     ?
  936.     if npages
  937.         display_start_MP()        ** Show boxes in form order
  938.         gen_npage_txt("key")    ** Multi-page switching
  939.     else
  940.         gen_display_text()
  941.         gen_inkey("key")
  942.     endif
  943.     ?
  944.     ?"SET COLOR TO {screen.color}"
  945.     endif    ** popups
  946.  
  947.     if .not.prggen
  948.     ?"RETURN"
  949.     if need_result
  950.         ??" key"
  951.     endif
  952.     endif
  953.  
  954.     * Generate supporting procedures
  955.     if npages            ** Multi-page
  956.        open_proc()
  957.        gen_newpage()        ** Multi-page page switching support
  958.     endif
  959.  
  960.     return    ** puretext is done!
  961. endif        ** puretext
  962.  
  963. *   ┌────────────────────────────────────────────────────┐
  964. *   │    Text-only display is done, finished, and gone.     │
  965. *   └────────────────────────────────────────────────────┘
  966.  
  967. if singleopt
  968.     ?
  969.     ?"SET ESCAPE ON"
  970. endif
  971. if .not.(puremenu .and. genpopup)
  972.     ?
  973.     ?"* display fixed text"
  974.     gen_display_text()          ** inline code if no popups, else a proc
  975. endif
  976. if savescreen
  977.     scrbufname = "mn_save_buf"
  978.     ?"PRIVATE {scrbufname}"
  979.     call_save_screen(menubox, scrbufname)
  980. endif
  981.  
  982. *   ┌───────────────────────────────────────────────────────────┐
  983. *   │    Except for pure menus and single-purpose append screen    │
  984. *   │    generate display of first record.            │
  985. *   └───────────────────────────────────────────────────────────┘
  986. ?
  987. if .not.puremenu .and. .not.singleadd
  988.     ?'DO {uniqname("disprec")}'
  989. endif
  990. if singleopt            ** There is no menu (a single-purpose screen)
  991. *    ┌───────────────────────────────────────────────────┐
  992. *    │    If only a single possible action.  Generate it.  │
  993. *    └───────────────────────────────────────────────────┘
  994.     if prggen .or. .not.need_result
  995.     ?"DO {singleproc}"
  996.     else
  997.     ?"RETURN {singleproc}()"
  998.     endif
  999. else
  1000. *    ┌───────────────────────────────────────────────────────────┐
  1001. *    │    Otherwise there's a choice of actions.  Call the menu.   │
  1002. *    └───────────────────────────────────────────────────────────┘
  1003.     ** There's several options
  1004.     ?'DO {uniqname("menu")}'
  1005. endif
  1006. *    ┌───────────────────────────────────────────────────────────┐
  1007. *    │    It's assumed that PRG's and menus don't return results   │
  1008. *    └───────────────────────────────────────────────────────────┘
  1009. ?
  1010. if .not.need_result        ** prggen .or. .not.singleopt
  1011.     if puremenu .and. savescreen
  1012.     call_restore_screen(menubox, scrbufname)
  1013.     endif
  1014.     ?"RETURN"
  1015. endif
  1016.  
  1017. *         ┌───────────────────────────────────────────────────────────┐
  1018. open_proc()   ** │  Open proc file, if any, and write procedure file header. │
  1019. *         └───────────────────────────────────────────────────────────┘
  1020. if .not.singleopt
  1021. *    ┌─────────────────────────────────────────┐
  1022. *    │        Code Generation.          │
  1023. *    ├─────────────────────────────────────────┤
  1024. *    │        Generate the menu.          │
  1025. *    └─────────────────────────────────────────┘
  1026. <<enduicode>>
  1027.  
  1028.  
  1029. **************************************************************************
  1030. *               Menu for {module}
  1031. **************************************************************************
  1032. <<uicode>>
  1033. gen_menu_proc(menuname, uniqname("mnprompt"), ;
  1034.         menubox, isbox, opt_words, opt_procs, ;
  1035.         (npages ? uniqname("newpage") : ""))
  1036. if puremenu
  1037.     return            ** For nothing but a menu, we're finished
  1038. endif
  1039. ?
  1040. ?
  1041. ?
  1042. ?
  1043. endif
  1044.  
  1045. *    ┌─────────────────────────────────────────┐
  1046. *    │         Code Generation.          │
  1047. *    ├─────────────────────────────────────────┤
  1048. *    │  Generate other supporting procedures.  │
  1049. *    └─────────────────────────────────────────┘
  1050.  
  1051. if want_proc(next_words)
  1052.     gen_nextrec()
  1053. endif
  1054.  
  1055. if want_proc(prev_words)
  1056.     gen_prevrec()
  1057. endif
  1058.  
  1059. if want_proc(top_words)
  1060.     gen_firstrec()
  1061. endif
  1062.  
  1063. if want_proc(bot_words)
  1064.     gen_lastrec()
  1065. endif
  1066.  
  1067. if want_proc(goto_words)
  1068.     gen_gotorec()
  1069. endif
  1070.  
  1071. if want_proc(find_words)
  1072.     gen_findrec()
  1073. endif
  1074.  
  1075. if want_proc(edit_words)
  1076.     if .not.got_ip_flds
  1077.     gen_msg("WARNING: Edit option chosen but there are no input fields")
  1078.     endif
  1079.     gen_editrec()
  1080. endif
  1081.  
  1082. if want_proc(add_words)
  1083.     if .not.got_ip_flds
  1084.     gen_msg("WARNING: Add option chosen but there are no input fields")
  1085.     endif
  1086.     gen_addrec()
  1087. endif
  1088.  
  1089. if edit_or_append    ** == wants editrec or wants addrec
  1090. *   ┌─────────────────────────────────────────────────────────────┐
  1091. *   │    All GET's and READ's are placed in a separate procedure   │
  1092. *   └─────────────────────────────────────────────────────────────┘
  1093.     if npages
  1094.     gen_MP_Gets_proc()    ** Special version of GETS_PROC for multi-page
  1095.     else
  1096.     gen_SP_Gets_proc()    ** Single-page version
  1097.     endif
  1098.     if Clipper() .and. split_read
  1099.     ** Must generate a special proc to stop a READ stmt
  1100.     gen_stop_read()
  1101.     endif
  1102. endif
  1103.  
  1104. if want_proc(del_words)
  1105.     gen_delrec()
  1106. endif
  1107.  
  1108. * - Custom 4 -
  1109.  
  1110. if msgbox
  1111.     gen_statmsg()
  1112. endif
  1113.  
  1114. if npages    ** Multi-page procedures
  1115. *   ┌──────────────────────────────────────────────────────────────┐
  1116. *   │    These routines do multipage displays for text and fields   │
  1117. *   └──────────────────────────────────────────────────────────────┘
  1118.     gen_newpage(.t.)    ** Generate NEWPAGE and PGTEXT procedures
  1119.     gen_MP_disprec()    ** Multi-page version of PROCs disprec
  1120.     gen_MP_dispmrec()    ** Multi-page memvar duplicates record display PROC
  1121. else
  1122. *   ┌──────────────────────────────────────────────────────────────┐
  1123. *   │    These routines do single page displays for text and fields │
  1124. *   └──────────────────────────────────────────────────────────────┘
  1125.     gen_SP_disprec()    ** Single page veriosn of PROCs disprec & dispmrec
  1126.     if need_dispmrec
  1127.     gen_SP_dispmrec() ** Single-page memvar duplicates record display PROC
  1128.     endif
  1129. endif
  1130.  
  1131.  
  1132. if genpopup .and. .not.savescreen
  1133. *   ┌──────────────────────────────────────────────────┐
  1134. *   │    This is required only for popups in a           │
  1135. *   │    language flavor not supporting screen saves.   │
  1136. *   └──────────────────────────────────────────────────┘
  1137.    gen_MP_display_text()
  1138. endif
  1139.  
  1140.  
  1141. *    ┌─────────────────────────────────────────┐
  1142. *    │          Code Generation.          │
  1143. *    ├─────────────────────────────────────────┤
  1144. *    │   Generation of multi user routines.      │
  1145. *    └─────────────────────────────────────────┘
  1146. if multi        ** Multi-user
  1147.     if lock_gen     ** Designer wants lock procedure generated.
  1148.     gen_lock_test()
  1149.     endif
  1150.     gen_unlk_recs()
  1151. endif
  1152.  
  1153. <<enduicode>>
  1154.